const { BaseCommand } = require("./base");

const glob = require("glob");
const fs = require("node:fs");
const path = require("node:path");
const { success, error, warn } = require("../utils/log_tool");
const { parse, stringify, processRename } = require("../utils/file_tool");

class BackupCommand extends BaseCommand {
    async execute() {
        const { sourceFolder, backupFolder, backupCfgs, verbose } =
            this.selfData;

        async function backup(bakCfg, filename) {
            const {
                sourceEncoding,
                sourceKeys,
                sourceType,
                backupFormat,
                backupFilename,
                backupRename,
                backupEncoding,
                backupPrettify,
            } = bakCfg;
            const filepath = path.join(sourceFolder, filename);
            let backupPath = path.join(
                backupFolder,
                backupFilename || filename,
            );
            let backupData;
            if (sourceType) {
                backupData = await parse(
                    fs.readFileSync(filepath, sourceEncoding),
                    sourceType,
                );
            } else {
                backupData = fs.readFileSync(filepath, {
                    encoding: backupEncoding,
                });
            }
            if (sourceKeys) {
                for (const key of sourceKeys) {
                    backupData = backupData[key];
                }
            }
            if (backupData === undefined) {
                warn(`未找到 ${filename} 的 ${sourceKeys} 字段`);
                return;
            }
            if (backupFormat) {
                backupData = await stringify(backupData, backupFormat);
            }
            if (backupPrettify) {
                backupData = await parse(backupData, backupPrettify.from);
                backupData = await stringify(backupData, backupPrettify.to);
            }
            if (backupRename) {
                backupPath = processRename(
                    backupPath,
                    backupRename,
                    backupData,
                );
            }
            const backupDir = path.dirname(backupPath);
            // 创建目录
            if (!fs.existsSync(backupDir)) {
                fs.mkdirSync(backupDir, {
                    recursive: true,
                });
            }
            fs.writeFileSync(backupPath, backupData, {
                encoding: backupEncoding,
            });
        }

        backupCfgs.forEach((bakCfg, index) => {
            if (typeof bakCfg === "string") {
                backupCfgs[index] = {
                    sourceFilename: bakCfg,
                };
            }
        });
        // 首次备份所有
        backupCfgs.forEach((cfg) => {
            const files = glob
                .sync(path.join(sourceFolder, cfg.sourceFilename))
                .map((v) => path.relative(sourceFolder, v));
            files.forEach((file) => {
                backup(cfg, file);
            });
        });

        // 监听文件夹变化
        fs.watch(
            sourceFolder,
            {
                recursive: true,
            },
            (eventType, filename) => {
                if (eventType === "change") {
                    const bakCfg = backupCfgs.find((cfg) => {
                        const files = glob
                            .sync(path.join(sourceFolder, cfg.sourceFilename))
                            .map((v) => path.relative(sourceFolder, v));
                        return files.some((file) => file === filename);
                    });
                    if (bakCfg) {
                        backup(bakCfg, filename)
                            .then(() => {
                                (verbose || bakCfg.verbose) &&
                                    success(`${filename} 备份成功`);
                            })
                            .catch((err) => {
                                error(`${filename} 备份异常 ${err}`);
                            });
                    }
                }
            },
        ).on("error", (err) => {
            error(`备份异常: ${err}`);
        });
    }
}

module.exports = {
    BackupCommand,
};
